package bluetooth

import (
	"context"
	"fmt"
	"math/rand"
	"net/http"
	"regexp"
	"sync"
	"time"

	"gitee.com/rw555/fdsmastergo/pkg/config"
	"gitee.com/rw555/fdsmastergo/pkg/logger"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// Server 蓝牙服务
type Server struct {
	scanner          *Scanner
	smokeDevices     map[string]*ScannedDevice // 烟感设备
	personnelDevices map[string]*ScannedDevice // 模拟人员设备
	devicesMux       sync.RWMutex
	stopChan         chan struct{}
	smokeFilter      *DeviceFilter // 烟感设备过滤器
	personnelFilter  *DeviceFilter // 模拟人员设备过滤器
	httpServer       *http.Server
	scanInterval     time.Duration
	scanDuration     time.Duration
	expireInterval   time.Duration
	expireDuration   time.Duration
	scanCtx          context.Context
	scanCancel       context.CancelFunc
	scanMutex        sync.Mutex // 保护扫描相关字段
	enableMockData   bool       // 是否启用模拟数据
}

// NewServer 创建新的蓝牙服务
func NewServer() (*Server, error) {

	// 创建服务器实例，但不设置过滤器
	server := &Server{
		scanner:          nil,
		smokeDevices:     make(map[string]*ScannedDevice),
		personnelDevices: make(map[string]*ScannedDevice),
		devicesMux:       sync.RWMutex{},
		stopChan:         make(chan struct{}),
		smokeFilter:      nil, // 先不设置过滤器
		personnelFilter:  nil, // 先不设置过滤器
		httpServer:       nil,
		scanInterval:     8 * time.Second,
		scanDuration:     5 * time.Second,
		expireInterval:   30 * time.Second,
		expireDuration:   120 * time.Second,
		scanCtx:          nil,
		scanCancel:       nil,
		scanMutex:        sync.Mutex{},
		enableMockData:   false,
	}

	// 设置默认过滤器（使用Compile而不是MustCompile）
	defaultPattern, err := regexp.Compile(".*")
	if err != nil {
		return nil, fmt.Errorf("编译默认正则表达式失败: %w", err)
	}
	server.smokeFilter = &DeviceFilter{NamePattern: defaultPattern, MinRSSI: -100}
	server.personnelFilter = &DeviceFilter{NamePattern: defaultPattern, MinRSSI: -100}

	// 加载配置
	_, err = server.loadBluetoothConfig()
	if err != nil {
		return nil, fmt.Errorf("加载蓝牙配置失败: %w", err)
	}

	// 创建扫描器
	scanner, err := NewScanner(server.smokeFilter, server.personnelFilter)
	if err != nil {
		return nil, err
	}

	// 设置设备发现回调
	server.scanner = scanner
	scanner.SetDeviceDiscoveredCallback(server.handleDeviceDiscovered)

	return server, nil
}

// Start 启动服务
func (s *Server) Start() error {
	// 启动HTTP服务：goroutine
	if err := s.startHTTPServer(); err != nil {
		return fmt.Errorf("启动HTTP服务失败: %w", err)
	}

	// 监控本机蓝牙设备是否可用：goroutine，如果蓝牙设备不可用，则会忽略掉蓝牙扫描定时任务的执行
	s.scanner.Start()

	// 启动扫描循环（使用本机蓝牙扫描蓝牙设备和定期清理过期设备）：goroutine
	s.startScanLoop()

	return nil
}

// Stop 停止服务
func (s *Server) Stop() {
	// 停止监控本机蓝牙设备是否可用
	s.scanner.Stop()

	// 停止扫描循环
	s.stopScanLoop()

	// 关闭HTTP服务
	if s.httpServer != nil {
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()
		if err := s.httpServer.Shutdown(ctx); err != nil {
			logger.SystemError("关闭HTTP服务失败", zap.Error(err))
		}
	}
}

// startHTTPServer 启动HTTP服务
func (s *Server) startHTTPServer() error {
	gin.SetMode(gin.ReleaseMode)
	router := gin.New()
	router.Use(gin.Recovery())

	// API路由
	v1 := router.Group("/api/v1")
	{
		v1.GET("/devices/smoke", s.handleGetSmokeDevices)         // 获取烟感设备
		v1.GET("/devices/personnel", s.handleGetPersonnelDevices) // 获取模拟人员设备
		v1.POST("/refresh-config", s.handleRefreshConfig)
	}

	s.httpServer = &http.Server{
		Addr:    "0.0.0.0:8083", // 监听所有网络接口
		Handler: router,
	}

	// 在后台启动HTTP服务
	go func() {
		if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			logger.SystemError("HTTP服务异常退出", zap.Error(err))
		}
	}()

	return nil
}

// handleRefreshConfig 处理配置刷新请求
func (s *Server) handleRefreshConfig(c *gin.Context) {
	configChanged, err := s.loadBluetoothConfig()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"message": "配置刷新失败", "error": err.Error()})
		return
	}

	// 如果扫描参数发生变化，重启扫描循环
	if configChanged {
		logger.SystemInfo("扫描参数已更改，重启扫描服务")

		// 停止当前的扫描循环
		s.stopScanLoop()

		// 启动新的扫描循环
		s.startScanLoop()
	}

	c.JSON(http.StatusOK, gin.H{"message": "配置已刷新"})
}

// handleGetSmokeDevices 处理获取烟感设备列表请求
func (s *Server) handleGetSmokeDevices(c *gin.Context) {
	// 直接调用getSmokeDevices，让它内部处理锁
	smokeDevices := s.getSmokeDevices()

	c.JSON(http.StatusOK, gin.H{
		"devices": smokeDevices,
	})
}

// handleGetPersonnelDevices 处理获取模拟人员设备列表请求
func (s *Server) handleGetPersonnelDevices(c *gin.Context) {
	// 直接调用getPersonnelDevices，让它内部处理锁
	personnelDevices := s.getPersonnelDevices()

	c.JSON(http.StatusOK, gin.H{
		"devices": personnelDevices,
	})
}

// cleanExpiredDevices 清理过期设备
func (s *Server) cleanExpiredDevices() {
	s.devicesMux.Lock()
	defer s.devicesMux.Unlock()

	expireDuration := s.expireDuration

	now := time.Now()

	// 清理烟感设备
	for mac, device := range s.smokeDevices {
		if now.Sub(device.LastSeen) > expireDuration {
			delete(s.smokeDevices, mac)
			logger.SystemInfo("烟感设备离线",
				zap.String("name", device.Name),
				zap.String("mac", device.MAC))
		}
	}

	// 清理模拟人员设备
	for mac, device := range s.personnelDevices {
		if now.Sub(device.LastSeen) > expireDuration {
			delete(s.personnelDevices, mac)
			logger.SystemInfo("模拟人员设备离线",
				zap.String("name", device.Name),
				zap.String("mac", device.MAC))
		}
	}
}

// scanLoop 持续扫描蓝牙设备
func (s *Server) scanLoop(ctx context.Context) {
	// 默认值
	scanInterval := s.scanInterval
	expireInterval := s.expireInterval

	// 扫描间隔时间，启用2个定时器分别控制扫描任务和清理任务
	ticker := time.NewTicker(scanInterval)
	cleanTicker := time.NewTicker(expireInterval)
	defer ticker.Stop()
	defer cleanTicker.Stop()
	for {
		select {
		case <-ctx.Done():
			return
		case <-s.stopChan:
			return
		case <-ticker.C:
			s.scanDevices()
		case <-cleanTicker.C:
			s.cleanExpiredDevices()
		}
	}
}

// scanDevices 扫描蓝牙设备
func (s *Server) scanDevices() {
	if !s.scanner.IsReady() {
		return
	}

	err := s.scanner.Scan(s.scanDuration)
	if err != nil {
		logger.SystemError("扫描蓝牙设备失败", zap.Error(err))
		return
	}
}

// getSmokeDevices 获取烟感设备列表
func (s *Server) getSmokeDevices() []*ScannedDevice {
	s.devicesMux.RLock()
	defer s.devicesMux.RUnlock()

	now := time.Now()
	var devices []*ScannedDevice

	// 从烟感设备映射中获取设备
	for _, dev := range s.smokeDevices {
		// 检查设备是否过期
		if now.Sub(dev.LastSeen) > s.expireDuration {
			continue
		}
		devices = append(devices, dev)
	}

	// 如果没有实际设备且启用了模拟数据，则生成模拟数据
	if len(devices) == 0 && s.enableMockData {
		now := time.Now()

		// 模拟设备1：烟感设备
		smokeDetector1 := &ScannedDevice{
			Name:     "[模拟] FDS-Smoke-001",
			MAC:      "AA:BB:CC:DD:EE:01",
			RSSI:     -65 + rand.Intn(10), // -65 到 -55 之间随机
			TxPower:  -55,
			LastSeen: now,
			Type:     DeviceTypeSmokeDetector,
			IsMock:   true,
		}

		// 模拟设备2：烟感设备
		smokeDetector2 := &ScannedDevice{
			Name:     "[模拟] FDS-Smoke-002",
			MAC:      "AA:BB:CC:DD:EE:02",
			RSSI:     -70 + rand.Intn(10), // -70 到 -60 之间随机
			TxPower:  -58,
			LastSeen: now,
			Type:     DeviceTypeSmokeDetector,
			IsMock:   true,
		}

		return []*ScannedDevice{smokeDetector1, smokeDetector2}
	}

	return devices
}

// getPersonnelDevices 获取模拟人员设备列表
func (s *Server) getPersonnelDevices() []*ScannedDevice {
	s.devicesMux.RLock()
	defer s.devicesMux.RUnlock()

	now := time.Now()
	var devices []*ScannedDevice

	// 从模拟人员设备映射中获取设备
	for _, dev := range s.personnelDevices {
		// 检查设备是否过期
		if now.Sub(dev.LastSeen) > s.expireDuration {
			continue
		}
		devices = append(devices, dev)
	}

	// 如果没有实际设备且启用了模拟数据，则生成模拟数据
	if len(devices) == 0 && s.enableMockData {
		now := time.Now()

		// 模拟设备3：模拟人员设备
		personnel1 := &ScannedDevice{
			Name:     "[模拟] FDS-Person-001",
			MAC:      "AA:BB:CC:DD:FF:01",
			RSSI:     -75 + rand.Intn(10), // -75 到 -65 之间随机
			TxPower:  -60,
			LastSeen: now,
			Type:     DeviceTypePersonnel,
			IsMock:   true,
		}

		// 模拟设备4：模拟人员设备
		personnel2 := &ScannedDevice{
			Name:     "[模拟] FDS-Person-002",
			MAC:      "AA:BB:CC:DD:FF:02",
			RSSI:     -80 + rand.Intn(10), // -80 到 -70 之间随机
			TxPower:  -62,
			LastSeen: now,
			Type:     DeviceTypePersonnel,
			IsMock:   true,
		}

		return []*ScannedDevice{personnel1, personnel2}
	}

	return devices
}

// handleDeviceDiscovered 处理设备发现事件
func (s *Server) handleDeviceDiscovered(device *ScannedDevice, deviceType string) {
	s.devicesMux.Lock()
	defer s.devicesMux.Unlock()

	// 根据设备类型存储到相应的映射中
	if deviceType == DeviceTypeSmokeDetector {
		s.smokeDevices[device.MAC] = device
	} else if deviceType == DeviceTypePersonnel {
		s.personnelDevices[device.MAC] = device
	}
}

func (s *Server) loadBluetoothConfig() (bool, error) {
	configClient := config.NewClient("http://localhost:8082")
	systemConfig, err := configClient.LoadConfigs()
	if err != nil {
		logger.SystemError("加载配置失败", zap.Error(err))
		return false, err
	}
	//configClient.PrintConfigs(systemConfig)

	s.devicesMux.Lock()
	defer s.devicesMux.Unlock()

	if namePattern, ok := systemConfig["bluetooth.smoke_filter.name_pattern"].(string); ok {
		pattern, err := regexp.Compile(namePattern)
		if err != nil {
			logger.SystemError("编译烟感设备名称正则表达式失败", zap.Error(err), zap.String("pattern", namePattern))
		} else {
			s.smokeFilter.NamePattern = pattern
		}
	}
	if minRSSI, ok := systemConfig["bluetooth.smoke_filter.min_rssi"].(float64); ok {
		s.smokeFilter.MinRSSI = int(minRSSI)
	}
	logger.SystemInfo("烟感设备过滤器配置", zap.Any("smokeFilter", s.smokeFilter))

	if namePattern, ok := systemConfig["bluetooth.personnel_filter.name_pattern"].(string); ok {
		pattern, err := regexp.Compile(namePattern)
		if err != nil {
			logger.SystemError("编译模拟人员设备名称正则表达式失败", zap.Error(err), zap.String("pattern", namePattern))
		} else {
			s.personnelFilter.NamePattern = pattern
		}
	}
	if minRSSI, ok := systemConfig["bluetooth.personnel_filter.min_rssi"].(float64); ok {
		s.personnelFilter.MinRSSI = int(minRSSI)
	}
	logger.SystemInfo("模拟人员设备过滤器配置", zap.Any("personnelFilter", s.personnelFilter))

	// 加载是否启用模拟数据的配置
	if enableMock, ok := systemConfig["bluetooth.enable_mock_data"].(bool); ok {
		s.enableMockData = enableMock
		logger.SystemInfo("更新模拟数据配置", zap.Bool("enableMockData", enableMock))
	}

	// 扫描参数是否有变化
	configChanged := false

	if interval, ok := systemConfig["bluetooth.scan.interval"].(float64); ok {
		newScanInterval := time.Duration(interval) * time.Second
		if newScanInterval != s.scanInterval {
			s.scanInterval = newScanInterval
			configChanged = true
			logger.SystemInfo("更新蓝牙扫描间隔", zap.Float64("seconds", interval))
		}
	}

	if scanDuration, ok := systemConfig["bluetooth.scan.duration"].(float64); ok {
		newScanDuration := time.Duration(scanDuration) * time.Second
		if newScanDuration != s.scanDuration {
			s.scanDuration = newScanDuration
			configChanged = true
			logger.SystemInfo("更新蓝牙扫描持续时间", zap.Float64("seconds", scanDuration))
		}
	}

	if interval, ok := systemConfig["bluetooth.expire.interval"].(float64); ok {
		newExpireInterval := time.Duration(interval) * time.Second
		if newExpireInterval != s.expireInterval {
			s.expireInterval = newExpireInterval
			configChanged = true
			logger.SystemInfo("更新蓝牙过期检查间隔", zap.Float64("seconds", interval))
		}
	}

	if expireDuration, ok := systemConfig["bluetooth.expire.duration"].(float64); ok {
		newExpireDuration := time.Duration(expireDuration) * time.Second
		if newExpireDuration != s.expireDuration {
			s.expireDuration = newExpireDuration
			configChanged = true
			logger.SystemInfo("更新蓝牙过期检查时间", zap.Float64("seconds", expireDuration))
		}
	}

	return configChanged, nil
}

// startScanLoop 启动扫描循环
func (s *Server) startScanLoop() {
	s.scanMutex.Lock()
	defer s.scanMutex.Unlock()

	// 创建新的上下文和取消函数
	ctx, cancel := context.WithCancel(context.Background())
	s.scanCtx = ctx
	s.scanCancel = cancel

	// 启动扫描循环
	go s.scanLoop(s.scanCtx)
}

// stopScanLoop 停止扫描循环
func (s *Server) stopScanLoop() {
	s.scanMutex.Lock()
	defer s.scanMutex.Unlock()

	// 取消当前的扫描循环
	if s.scanCancel != nil {
		s.scanCancel()
	}
}
